package lq.cloud.studyserversystem.configure;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import lq.cloud.studyserversystem.properties.StudyServerSystemProperties;
import lq.cloud.studyserversystem.properties.StudySwaggerProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.*;

/**
 * @program: cloud-study
 * @description: mybatis-plus 分页插件配置
 * @author: LQ
 * @create: 2021-02-03 13:57
 */

@EnableSwagger2
@Configuration
public class StudyWebConfigure {

    @Autowired
    private StudyServerSystemProperties systemProperties;

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        List<ISqlParser> sqlParserList = new ArrayList<>();
        sqlParserList.add(new BlockAttackSqlParser());
        paginationInterceptor.setSqlParserList(sqlParserList);
        return paginationInterceptor;
    }

    @Bean
    public Docket swaggerApi() {
        StudySwaggerProperties swagger = systemProperties.getSwagger();
        return new Docket(DocumentationType.SWAGGER_2).select()
                // apis设置需要添加进swagger管理的路径
                .apis(RequestHandlerSelectors.basePackage(swagger.getBasePackage()))
                // 表示Controller里的所有方法都纳入。
                .paths(PathSelectors.any()).build()
                // apiInfo用于定义一些API页面信息，比如作者名称，邮箱，网站链接，开源协议等等。
                .apiInfo(apiInfo(swagger))
                // 构建安全策略，比如配置认证模型，scope等内容；
                .securitySchemes(Collections.singletonList(securityScheme(swagger)))
                // 安全上下文,只有配置了安全上下文的接口才能使用令牌获取资源
                .securityContexts(Collections.singletonList(securityContext(swagger)));

    }

    /**
     * 配置安全上下文
     * 只有配置了安全上下文的接口才能使用令牌获取资源
     * 通过study_oauth_swagger名称关联了上面定义的安全策略,study_oauth_swagger在配置中配置
     *
     * @param swagger
     * @return
     */
    private SecurityContext securityContext(StudySwaggerProperties swagger) {
        return SecurityContext.builder().securityReferences(Collections
                // 通过配置的名称关联安全策略,scope为配置的scope,需要和和auth模块里定义的一致
                .singletonList(new SecurityReference(swagger.getName(), scopes(swagger))))
                // forPaths(PathSelectors.any())设置所有API接口都用这个安全上下文。
                .forPaths(PathSelectors.any()).build();
    }

    /**
     * 设置scope
     * @param swagger
     * @return
     */
    private AuthorizationScope[] scopes(StudySwaggerProperties swagger) {
        // 读取配置中的scpoe
        return new AuthorizationScope[]{new AuthorizationScope(swagger.getScope(), "")};
    }

    /**
     * 用于配置安全策略，比如配置认证模型，scope等内容；
     * 通过OAuthBuilder对象构建安全策略,
     * 主要配置了认证类型为ResourceOwnerPasswordCredentialsGrant（即密码模式）
     *
     * @param swagger
     * @return
     */
    private SecurityScheme securityScheme(StudySwaggerProperties swagger) {
        // 配置认证类型为ResourceOwnerPasswordCredentialsGrant,设置认证路径为配置的认证的路径
        GrantType grantType = new ResourceOwnerPasswordCredentialsGrant(swagger.getGrantUrl());
        return new OAuthBuilder().name(swagger.getName()).grantTypes(Collections.singletonList(grantType)).scopes(Arrays.asList(scopes(swagger))).build();
    }

    /**
     * swagger 展示信息
     *
     * @param swagger
     * @return
     */
    private ApiInfo apiInfo(StudySwaggerProperties swagger) {
        return new ApiInfo(swagger.getTitle(), swagger.getDescription(), swagger.getVersion(), null, new Contact(swagger.getAuthor(), swagger.getUrl(), swagger.getEmail()), swagger.getLicense(), swagger.getLicenseUrl(), Collections.emptyList());
    }
}

